(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('babel-runtime/core-js/object/keys'), require('babel-runtime/core-js/promise'), require('babel-runtime/helpers/extends'), require('babel-runtime/helpers/objectWithoutProperties'), require('babel-runtime/core-js/json/stringify'), require('babel-runtime/core-js/object/assign'), require('babel-runtime/core-js/symbol'), require('babel-runtime/core-js/object/define-property'), require('babel-runtime/helpers/classCallCheck'), require('babel-runtime/helpers/createClass')) :
	typeof define === 'function' && define.amd ? define(['babel-runtime/core-js/object/keys', 'babel-runtime/core-js/promise', 'babel-runtime/helpers/extends', 'babel-runtime/helpers/objectWithoutProperties', 'babel-runtime/core-js/json/stringify', 'babel-runtime/core-js/object/assign', 'babel-runtime/core-js/symbol', 'babel-runtime/core-js/object/define-property', 'babel-runtime/helpers/classCallCheck', 'babel-runtime/helpers/createClass'], factory) :
	(global.stat = factory(global._Object$keys,global._Promise,global._extends,global._objectWithoutProperties,global._JSON$stringify,global._Object$assign,global._Symbol,global._Object$defineProperty,global._classCallCheck,global._createClass));
}(this, (function (_Object$keys,_Promise,_extends,_objectWithoutProperties,_JSON$stringify,_Object$assign,_Symbol,_Object$defineProperty,_classCallCheck,_createClass) { 'use strict';

	_Object$keys = _Object$keys && _Object$keys.hasOwnProperty('default') ? _Object$keys['default'] : _Object$keys;
	_Promise = _Promise && _Promise.hasOwnProperty('default') ? _Promise['default'] : _Promise;
	_extends = _extends && _extends.hasOwnProperty('default') ? _extends['default'] : _extends;
	_objectWithoutProperties = _objectWithoutProperties && _objectWithoutProperties.hasOwnProperty('default') ? _objectWithoutProperties['default'] : _objectWithoutProperties;
	_JSON$stringify = _JSON$stringify && _JSON$stringify.hasOwnProperty('default') ? _JSON$stringify['default'] : _JSON$stringify;
	_Object$assign = _Object$assign && _Object$assign.hasOwnProperty('default') ? _Object$assign['default'] : _Object$assign;
	_Symbol = _Symbol && _Symbol.hasOwnProperty('default') ? _Symbol['default'] : _Symbol;
	_Object$defineProperty = _Object$defineProperty && _Object$defineProperty.hasOwnProperty('default') ? _Object$defineProperty['default'] : _Object$defineProperty;
	_classCallCheck = _classCallCheck && _classCallCheck.hasOwnProperty('default') ? _classCallCheck['default'] : _classCallCheck;
	_createClass = _createClass && _createClass.hasOwnProperty('default') ? _createClass['default'] : _createClass;

	var xhr = (function () {
		var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
		    _ref$method = _ref.method,
		    method = _ref$method === undefined ? 'GET' : _ref$method,
		    _ref$url = _ref.url,
		    url = _ref$url === undefined ? '' : _ref$url,
		    _ref$data = _ref.data,
		    data = _ref$data === undefined ? {} : _ref$data,
		    _ref$headers = _ref.headers,
		    headers = _ref$headers === undefined ? {
			'Content-Type': 'application/json; charset=UTF-8'
		} : _ref$headers;

		if (!url) return _Promise.reject('url 不能为空');

		var xhr = new XMLHttpRequest();
		xhr.open(method, url);
		xhr.timeout = 5000;
		_Object$keys(headers).forEach(function (item) {
			return xhr.setRequestHeader(item, headers[item]);
		});

		return new _Promise(function (resolve, reject) {
			xhr.onreadystatechange = function () {
				return xhr.readyState === 4 && (xhr.status === 200 ? resolve({ status: 200, data: xhr.responseText }) : reject({ status: xhr.status, data: xhr.statusText }));
			};

			xhr.send(data);
		});
	});

	var getLocation = function getLocation() {
	  return window.location;
	};

	var getQuery = function getQuery() {
	  var search = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getLocation().href.split('?')[1];
	  return search ? search.split('&').map(function (item) {
	    return item.split('=');
	  }).reduce(function (a, b) {
	    return b[1] ? (a[b[0]] = b[1]) && a : (a[b[0]] = b[1]) || a;
	  }, {}) : {};
	};

	var getData = (function () {
		var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

		var _ref$action = _ref.action,
		    action = _ref$action === undefined ? 'view' : _ref$action,
		    _ref$target = _ref.target,
		    target = _ref$target === undefined ? '页面' : _ref$target,
		    _ref$page = _ref.page,
		    page = _ref$page === undefined ? document.title || getLocation().href : _ref$page,
		    _ref$parentPage = _ref.parentPage,
		    parentPage = _ref$parentPage === undefined ? '' : _ref$parentPage,
		    _ref$pageParams = _ref.pageParams,
		    pageParams = _ref$pageParams === undefined ? getQuery() : _ref$pageParams,
		    _ref$parentParams = _ref.parentParams,
		    parentParams = _ref$parentParams === undefined ? {} : _ref$parentParams,
		    _ref$actionParams = _ref.actionParams,
		    actionParams = _ref$actionParams === undefined ? {} : _ref$actionParams,
		    params = _objectWithoutProperties(_ref, ['action', 'target', 'page', 'parentPage', 'pageParams', 'parentParams', 'actionParams']);

		return _extends({
			action: action,
			target: target,
			page: page,
			parentPage: parentPage,
			pageParams: pageParams,
			parentParams: parentParams,
			actionParams: actionParams
		}, params);
	});

	var isFn = function isFn(fn) {
	  return typeof fn === 'function';
	};

	var beforeDispose = function beforeDispose(from, count, self, params) {
		var id = from[count]++;

		from[self].push(_extends({ id: id }, params));

		return function () {
			var index = from[self].findIndex(function (item) {
				return item.id === id;
			});

			if (index > -1) return from[self].splice(index, 1);
		};
	};

	var getListenerData = function getListenerData(from, params, _ref) {
		var currentPath = _ref.currentPath,
		    pathname = _ref.pathname,
		    currentQuery = _ref.currentQuery;


		return from.listeners.reduce(function (a, b) {
			if (new RegExp('^' + b.reg + '/').test(currentPath + '/')) {
				if (isFn(b.pipe)) {
					var getParams = b.pipe(a, { fullPath: pathname, path: currentPath, query: _extends({}, currentQuery) }) || {};

					return _Object$assign(getParams, a);
				}

				return a;
			}

			return a;
		}, params);
	};

	var GT = function GT(key) {
	  return window.sessionStorage.getItem(key);
	};
	var ST = function ST(key, value) {
	  return window.sessionStorage.setItem(key, value);
	};

	var _GT = function _GT(key) {
	  var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '{}';
	  return JSON.parse(GT(key) || ST(key, type) || type);
	};
	var _ST = function _ST(key, value) {
	  return ST(key, _JSON$stringify(value));
	};

	var getPageCache = function getPageCache() {
	  return _GT('SXYJ_STAT_PAGE');
	};
	var setPageCache = function setPageCache(value) {
	  return _ST('SXYJ_STAT_PAGE', value);
	};

	var getNodeCache = function getNodeCache(path) {
	  return _GT('SXYJ_STAT_NODE-' + path);
	};
	var setNodeCache = function setNodeCache(path, value) {
	  return _ST('SXYJ_STAT_NODE-' + path, value);
	};

	var report = _Symbol('report');
	var reportEnd = _Symbol('reportEnd');
	var getNodeList = _Symbol('getNodeList');
	var setNodeList = _Symbol('setNodeList');
	var getEventList = _Symbol('getEventList');
	var setEventList = _Symbol('setEventList');
	var formatData = _Symbol('formatData');
	var getBaseData = _Symbol('getBaseData');
	var init = _Symbol('init');

	var version = "4.3.1";

	var id = 0;

	var readOnly = {};
	var readOnlyPublic = {
		pageReportHistory: getPageCache(),

		nodeReportHistory: {},

		reportCache: [],

		listenerId: 0,
		listeners: [],

		dataPipesCount: 0,
		dataPipes: [],

		initPlugins: [],

		addNodeHooksCount: 0,
		addNodeHooks: [],

		reportHooksCount: 0,
		reportHooks: []
	};

	var Stat = function () {
		function Stat() {
			var _this = this;

			var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

			var _ref$report = _ref.report,
			    _report = _ref$report === undefined ? null : _ref$report,
			    _ref$url = _ref.url,
			    url = _ref$url === undefined ? '' : _ref$url,
			    _ref$offset = _ref.offset,
			    offset = _ref$offset === undefined ? 0 : _ref$offset,
			    _ref$showConsole = _ref.showConsole,
			    showConsole = _ref$showConsole === undefined ? true : _ref$showConsole,
			    _ref$oncePageView = _ref.oncePageView,
			    oncePageView = _ref$oncePageView === undefined ? false : _ref$oncePageView,
			    _ref$onceNodeView = _ref.onceNodeView,
			    onceNodeView = _ref$onceNodeView === undefined ? false : _ref$onceNodeView,
			    _ref$closeAutoNodeRep = _ref.closeAutoNodeReport,
			    closeAutoNodeReport = _ref$closeAutoNodeRep === undefined ? false : _ref$closeAutoNodeRep,
			    _ref$plugins = _ref.plugins,
			    plugins = _ref$plugins === undefined ? [] : _ref$plugins,
			    options = _objectWithoutProperties(_ref, ['report', 'url', 'offset', 'showConsole', 'oncePageView', 'onceNodeView', 'closeAutoNodeReport', 'plugins']);

			_classCallCheck(this, Stat);

			_initialiseProps.call(this);

			[{ key: 'version', value: version }, { key: '_id', value: id++ }, { key: 'pathnameOffset', value: offset }].forEach(function (item) {
				return _Object$defineProperty(_this, item.key, { value: item.value });
			});

			this.options = _extends({
				report: _report,
				url: url,
				showConsole: showConsole,
				oncePageView: oncePageView,
				onceNodeView: onceNodeView,
				closeAutoNodeReport: closeAutoNodeReport,
				nextParams: {} }, options);

			readOnly[this._id] = {
				currentPath: '',
				lastPath: '',

				nodeList: {},

				eventList: {},

				listenerId: 0,
				listeners: [],

				dataPipesCount: 0,
				dataPipes: [],

				addNodeHooksCount: 0,
				addNodeHooks: [],

				reportHooksCount: 0,
				reportHooks: []
			};

			try {
				plugins.forEach(function (plugin) {
					if (isFn(plugin.apply)) plugin.apply.call(plugin, _this);else if (isFn(plugin)) plugin.call(null, _this);
				});
			} catch (error) {
				console.error('stat plugins error!', error);
			}

			this[init]();
		}

		_createClass(Stat, [{
			key: reportEnd,
			value: function value(fn, sourceData) {
				var _this2 = this;

				return new _Promise(function (resolve) {
					return resolve(fn());
				}).then(function (res) {
					readOnlyPublic.reportHooks.forEach(function (item) {
						return isFn(item.callback) && item.callback(null, res, sourceData);
					});
					readOnly[_this2._id].reportHooks.forEach(function (item) {
						return isFn(item.callback) && item.callback(null, res, sourceData);
					});

					return res;
				}).catch(function (err) {
					readOnlyPublic.reportHooks.forEach(function (item) {
						return isFn(item.callback) && item.callback(err, null, sourceData);
					});
					readOnly[_this2._id].reportHooks.forEach(function (item) {
						return isFn(item.callback) && item.callback(err, null, sourceData);
					});

					return err;
				});
			}
		}, {
			key: report,
			value: function value(datas) {
				for (var _len = arguments.length, arg = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
					arg[_key - 1] = arguments[_key];
				}

				var _datas = this[formatData](datas);

				if (!_datas.length) return;

				var cache = readOnlyPublic.reportCache;
				var _options = this.options,
				    _report = _options.report,
				    url = _options.url,
				    showConsole = _options.showConsole;


				showConsole && console.log('Stat datas: ', _datas);

				if (isFn(_report)) {
					cache.length && cache.splice(0, cache.length).forEach(function (__datas) {
						return _report(__datas);
					});

					return this[reportEnd](function () {
						return _report.apply(undefined, [_datas].concat(arg));
					}, [_datas].concat(arg));
				} else if (url) return this[reportEnd](function () {
					return xhr({ method: 'POST', url: url, data: _JSON$stringify(_datas) });
				}, [_datas].concat(arg));else cache.push(_datas);
			}
		}, {
			key: formatData,
			value: function value(datas) {
				var publicData = readOnlyPublic.dataPipes.reduce(function (a, b) {
					return isFn(b.pipe) ? b.pipe(a) || a : a;
				}, datas);
				var ownData = readOnly[this._id].dataPipes.reduce(function (a, b) {
					return isFn(b.pipe) ? b.pipe(a) || a : a;
				}, publicData);

				return ownData;
			}
		}, {
			key: getBaseData,
			value: function value(params) {
				var currentPath = this.currentPath;

				var _getLocation = getLocation(),
				    pathname = _getLocation.pathname;

				var currentQuery = getQuery();

				var publicParams = getListenerData(readOnlyPublic, _extends({}, this.options.nextParams, params), { currentPath: currentPath, pathname: pathname, currentQuery: currentQuery });
				var ownParams = getListenerData(readOnly[this._id], publicParams, { currentPath: currentPath, pathname: pathname, currentQuery: currentQuery });

				return getData(ownParams);
			}
		}, {
			key: getNodeList,
			value: function value() {
				var currentPath = this.currentPath;
				var id = this._id;

				return readOnly[id].nodeList[currentPath] || {};
			}
		}, {
			key: setNodeList,
			value: function value(nodeId, _ref2) {
				var el = _ref2.el,
				    params = _objectWithoutProperties(_ref2, ['el']);

				var currentPath = this.currentPath;
				var lastPath = this.lastPath;
				var id = this._id;
				var nodes = readOnly[id].nodeList;

				if (nodes[lastPath]) nodes[lastPath] = null;
				if (!nodes[currentPath]) nodes[currentPath] = {};

				return nodes[currentPath][nodeId] = _extends({ el: el }, params);
			}
		}, {
			key: getEventList,
			value: function value() {
				var currentPath = this.currentPath;
				var id = this._id;

				return readOnly[id].eventList[currentPath] || {};
			}
		}, {
			key: setEventList,
			value: function value(nodeId, event) {
				var currentPath = this.currentPath;
				var lastPath = this.lastPath;
				var id = this._id;
				var events = readOnly[id].eventList;

				if (events[lastPath]) events[lastPath] = null;
				if (!events[currentPath]) events[currentPath] = {};

				return events[currentPath][nodeId] = event;
			}
		}, {
			key: init,
			value: function value() {
				var _this3 = this;

				if (!this.options.closeAutoNodeReport) {
					var scrollTimer = null;
					document.addEventListener('scroll', function () {
						clearTimeout(scrollTimer);
						scrollTimer = setTimeout(function () {
							return _this3.nodeReport();
						}, 800);
					}, {
						capture: true,
						once: false,
						passive: true
					});

					this.on('addNode', function () {
						return _this3.nodeReport();
					});
				}
			}
		}, {
			key: 'currentPath',
			get: function get() {
				var id = this._id;
				var path = '/' + (getLocation().pathname.split('/')[this.pathnameOffset] || '');

				if (path !== readOnly[id].currentPath) readOnly[id].lastPath = readOnly[id].currentPath;

				return readOnly[id].currentPath = path;
			}
		}, {
			key: 'lastPath',
			get: function get() {
				return readOnly[this._id].lastPath;
			}
		}]);

		return Stat;
	}();

	Stat.on = function (type, callback) {
		return beforeDispose(readOnlyPublic, type + 'HooksCount', type + 'Hooks', { callback: callback });
	};

	Stat.listen = function (reg, pipe) {
		return beforeDispose(readOnlyPublic, 'listenerId', 'listeners', { reg: reg, pipe: pipe });
	};

	Stat.pipe = function (pipe) {
		return beforeDispose(readOnlyPublic, 'dataPipesCount', 'dataPipes', { pipe: pipe });
	};

	var _initialiseProps = function _initialiseProps() {
		var _this4 = this;

		this.setOptions = function () {
			var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

			_Object$assign(_this4.options, options);

			if (isFn(options.report)) {
				var cache = readOnlyPublic.reportCache;

				cache.length && cache.splice(0, cache.length).forEach(function (datas) {
					return options.report(datas);
				});
			}

			return _this4.options;
		};

		this.setNextParams = function () {
			var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
			return _this4.options.nextParams = params;
		};

		this.on = function (type, callback) {
			return beforeDispose(readOnly[_this4._id], type + 'HooksCount', type + 'Hooks', { callback: callback });
		};

		this.listen = function (reg, pipe) {
			return beforeDispose(readOnly[_this4._id], 'listenerId', 'listeners', { reg: reg, pipe: pipe });
		};

		this.pipe = function (pipe) {
			return beforeDispose(readOnly[_this4._id], 'dataPipesCount', 'dataPipes', { pipe: pipe });
		};

		this.addNode = function (el) {
			var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

			var id = _ref3.id,
			    _ref3$unView = _ref3.unView,
			    unView = _ref3$unView === undefined ? false : _ref3$unView,
			    _ref3$unClick = _ref3.unClick,
			    unClick = _ref3$unClick === undefined ? false : _ref3$unClick,
			    clickEvent = _ref3.clickEvent,
			    params = _objectWithoutProperties(_ref3, ['id', 'unView', 'unClick', 'clickEvent']);

			if (!id) return false;

			_this4[setNodeList](id, { el: el, unView: unView, params: params });

			el.removeEventListener('click', _this4[getEventList]()[id]);

			_this4[setEventList](id, function () {
				if (unClick) return;

				isFn(clickEvent) ? clickEvent(params) : _this4.clickReport(params);
			});
			el.addEventListener('click', _this4[getEventList]()[id]);

			clearTimeout(_this4.addNodeHooksTimer);
			_this4.addNodeHooksTimer = setTimeout(function () {
				readOnlyPublic.addNodeHooks.forEach(function (item) {
					return typeof item.callback === 'function' && item.callback();
				});
				readOnly[_this4._id].addNodeHooks.forEach(function (item) {
					return typeof item.callback === 'function' && item.callback();
				});
			}, 800);

			return true;
		};

		this.removeNode = function (id) {
			if (!id) return false;
			var nodes = _this4[getNodeList]();
			var events = _this4[getEventList]();

			nodes[id] && nodes[id].el.removeEventListener('click', events[id]);

			delete events[id];
			delete nodes[id];

			return true;
		};

		this.nodeReport = function () {
			for (var _len2 = arguments.length, arg = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
				arg[_key2] = arguments[_key2];
			}

			var path = _this4.currentPath;
			var lastPath = _this4.lastPath;
			var history = readOnlyPublic.nodeReportHistory;
			var once = _this4.options.onceNodeView;

			if (once) {
				history[path] = getNodeCache(path);
			} else {
				if (history[lastPath]) history[lastPath] = null;

				if (!history[path]) history[path] = {};
			}

			var nodes = _this4[getNodeList]();

			var ids = _Object$keys(nodes);
			var _window = window,
			    innerHeight = _window.innerHeight,
			    innerWidth = _window.innerWidth;

			var reportList = [];

			ids.forEach(function (id) {
				if (history[path][id]) return delete nodes[id];

				var _nodes$id = nodes[id],
				    el = _nodes$id.el,
				    unView = _nodes$id.unView,
				    params = _nodes$id.params;

				if (unView) return;
				if (!el.getBoundingClientRect) return;

				var _el$getBoundingClient = el.getBoundingClientRect(),
				    left = _el$getBoundingClient.left,
				    top = _el$getBoundingClient.top;

				var offsetWidth = el.offsetWidth,
				    offsetHeight = el.offsetHeight;


				if (left >= 0 - offsetWidth / 3 * 2 && left <= innerWidth - offsetWidth / 3 && top >= 0 - offsetHeight / 3 * 2 && top <= innerHeight - offsetHeight / 3) {
					reportList.push(params);
					delete nodes[id];
					history[path][id] = true;
				}
			});

			once && setNodeCache(path, history[path]);

			return _this4[report].apply(_this4, [reportList.map(function (params) {
				return _this4[getBaseData](_extends({ action: 'view' }, params));
			})].concat(arg));
		};

		this.pageReport = function (params) {
			for (var _len3 = arguments.length, arg = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
				arg[_key3 - 1] = arguments[_key3];
			}

			if (_this4.options.oncePageView) {
				var history = readOnlyPublic.pageReportHistory;

				if (history[params.page]) return;

				history[params.page] = true;
				setPageCache(history);
			}

			return _this4[report].apply(_this4, [[_this4[getBaseData](_extends({ action: 'view' }, params))]].concat(arg));
		};

		this.clickReport = function (params) {
			for (var _len4 = arguments.length, arg = Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
				arg[_key4 - 1] = arguments[_key4];
			}

			return _this4[report].apply(_this4, [[_this4[getBaseData](_extends({ action: 'click' }, params))]].concat(arg));
		};

		this.getCurrentData = function (params) {
			return _this4[formatData]([_this4[getBaseData](params)]);
		};
	};

	return Stat;

})));
